namespace ContosoUniversity.Services.AppServices
{
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using ContosoUniversity.DAL;
    using Models;
    using NRepository.Core;
    using NRepository.EntityFramework;
    using NRepository.EntityFramework.Query;

    public class ContosoApplicationService : IContosoApplicationService
    {
        private readonly IRepository _Repository;

        public ContosoApplicationService(IRepository repository)
        {
            _Repository = repository;
        }

        public void AddInstructorWithCourses(Instructor instructor, IEnumerable<int> courses)
        {
            if (courses != null)
            {
                instructor.Courses = _Repository.GetEntities<Course>(
                    new FindByIdsSpecificationStrategy<Course>(p => p.CourseID, courses))
                    .ToList();
            }

            _Repository.Add(instructor);
            _Repository.Save();
        }

        public void AddStudent(Student student)
        {
            _Repository.Add(student);
            _Repository.Save();
        }

        public void AddDepartment(Department department)
        {
            _Repository.Add(department);
            _Repository.Save();
        }

        public void DeleteCourse(int courseId)
        {
            var courseToDelete = new Course { CourseID = courseId };
            _Repository.UpdateEntityState(courseToDelete, EntityState.Deleted);
            _Repository.Save();
        }

        public void DeleteDepartment(int departmentID)
        {
            var department = _Repository.GetEntity<Department>(p => p.DepartmentID == departmentID);
            _Repository.Delete(department);
            _Repository.Save();
        }

        public void DeleteInstructor(int instructorId)
        {
            var deletedInstructor = _Repository.GetEntity<Instructor>(
                p => p.ID == instructorId,
                new EagerLoadingQueryStrategy<Instructor>(
                    p => p.OfficeAssignment));

            deletedInstructor.OfficeAssignment = null;

            _Repository.Delete(deletedInstructor);
            _Repository.Save();
        }

        public void DeleteStudent(int studentId)
        {
            var deletedStudent = new Student { ID = studentId };
            _Repository.Modify(deletedStudent);
            _Repository.Save();
        }

        public void ModifyCourse(Course course)
        {
            _Repository.Modify(course);
            _Repository.Save();
        }

        public void ModifyDepartment(Department department)
        {
            _Repository.Modify(department);
            _Repository.Save();
        }

        public void ModifyStudent(Student student)
        {
            _Repository.Modify(student);
            _Repository.Save();
        }

        public int UpdateCourseCredits(int multiplier)
        {
            return _Repository.ExecuteStoredProcudure("UPDATE Course SET Credits = Credits * {0}", multiplier);
        }

        public void UpdateInstructorAndCourses(Instructor instructorToUpdate, IEnumerable<int> courses)
        {
            var instructor = _Repository.GetEntity<Instructor>(p => p.ID == instructorToUpdate.ID);

            // Removals first
            instructor.Courses.Clear();
            if (instructor.OfficeAssignment != null && instructorToUpdate.OfficeAssignment == null)
                _Repository.Delete(instructor.OfficeAssignment);

            // Update properties
            instructor.FirstMidName = instructorToUpdate.FirstMidName;
            instructor.LastName = instructorToUpdate.LastName;
            instructor.HireDate = instructorToUpdate.HireDate;
            instructor.OfficeAssignment = instructorToUpdate.OfficeAssignment;
            instructor.Courses = _Repository.GetEntities<Course>(
                new FindByIdsSpecificationStrategy<Course>(p => p.CourseID, courses))
                .ToList();

            _Repository.Modify(instructor);
            _Repository.Save();
        }

        public void AddNewCourse(Course course)
        {
            _Repository.Add(course);
            _Repository.Save();
        }
    }
}
